#!/usr/bin/env python
# -*-  coding: utf-8 -*-
#   
#   Copyright © 2008, 2009, 2010 Jan Svec <honza.svec@gmail.com> and Filip Jurcicek <filip.jurcicek@gmail.com>
#   
#   This file is part of Gmail Backup.
#
#   Gmail Backup is free software: you can redistribute it and/or modify it
#   under the terms of the GNU General Public License as published by the Free
#   Software Foundation, either version 3 of the License, or (at your option)
#   any later version.
#
#   Gmail Backup is distributed in the hope that it will be useful, but WITHOUT
#   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
#   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
#   more details.
#
#   You should have received a copy of the GNU General Public License along
#   with Gmail Backup.  If not, see <http://www.gnu.org/licenses/
#
#   See LICENSE file for license details
#
#   With changes by Jesper Hertel <jesper.hertel@gmail.com> (JH).

import imaplib
import time

_submoduleListForVersioning = []
import versioning; _revisionInfo = versioning.getRevisionInfoFromTagsAndSubModules('$Revision$', '$Date$', _submoduleListForVersioning)


def getImap4InternalDateStringFromDateTimeTuple(dateTimeTuple):
    imap4InternalDateString = imaplib.Time2Internaldate(dateTimeTuple)  # Note that Time2Internaldate() can handle several different input formats.
    return imap4InternalDateString


def getImap4InternalDateStringFromSecondsSinceTheEpoch(secondsSinceTheEpoch):
    imap4InternalDateString = imaplib.Time2Internaldate(secondsSinceTheEpoch) # Note that Time2Internaldate() can handle several different input formats.
    return imap4InternalDateString


def convertDateYYYYMMDDToImap4InternalDateString(dateYYYYMMDD):
    ''''Convert a date string in the form "YYYYMMDD", e.g. "20130716" 
    (for July 16, 2013) to an IMAP4 INTERNALDATE string, i.e. a string 
    in the form: '"DD-Mmm-YYYY HH:MM:SS +HHMM"' (including the double 
    quotes), e.g.'"16-Jul-2013 00:00:00 +0000"'. 
    
    Note that the "+0000" varies with your current locale. 
    (JH: I am not sure if that is on purpose?).
    
    Docstring tests:
    
        The time zone part varies with the local settings, therefore we filter
        the time zone away in these tests with [:-7].
    
        A contemporary date at the time of writing this:
        >>> convertDateYYYYMMDDToImap4InternalDateString("20130716")[:-7]
        '"16-Jul-2013 00:00:00'
        
        The returned IMAP dates ends with '"':
        >>> convertDateYYYYMMDDToImap4InternalDateString("20130716")[-1:]
        '"'
        
        The Unix Epoch does not always go well, at least not when in time 
        zone +0200. But this test would depend on the current time zone, so 
        we cannot state it here. But in Denmark it would be like this:
        #>>> convertDateYYYYMMDDToImap4InternalDateString("19700101")[:-7]
        #Traceback (most recent call last):
        #OverflowError: mktime argument out of range
        
        Shortly after the Unix Epoch:
        >>> convertDateYYYYMMDDToImap4InternalDateString("19700102")[:-7]
        '" 2-Jan-1970 00:00:00'
    
        Shortly before the Unix Epoch:
        >>> convertDateYYYYMMDDToImap4InternalDateString("19691231")
        Traceback (most recent call last):
        OverflowError: mktime argument out of range
    '''
    secondsSinceEpoch = convertDateYYYYMMDDToSecondsSinceEpoch(dateYYYYMMDD)
    imap4InternalDateString = getImap4InternalDateStringFromSecondsSinceTheEpoch(secondsSinceEpoch)
    return imap4InternalDateString


def convertDateTimeTupleToDateYYYYMMDD(lastTimeDateTimeTuple):
    '''Return a date string in the form "20130716" (for July 16, 2013) from a
    DateTimeTuple such as (2013, 7, 16, 13, 51, 18, 2, 317, 0).
    
    Docstring tests:
    
        Contemporary date:
        >>> convertDateTimeTupleToDateYYYYMMDD((2013, 7, 16, 13, 51, 18, 2, 317, 0))
        '20130716'
        
        Future date:
        >>> convertDateTimeTupleToDateYYYYMMDD((2113, 12, 31, 13, 51, 18, 2, 317, 0))
        '21131231'
        
        Invalid dates:
        >>> convertDateTimeTupleToDateYYYYMMDD((2113, 12, 32, 13, 51, 18, 2, 317, 0))
        Traceback (most recent call last):
        ValueError: day of month out of range
        >>> convertDateTimeTupleToDateYYYYMMDD((2113, 13, 32, 13, 51, 18, 2, 317, 0))
        Traceback (most recent call last):
        ValueError: month out of range
        >>> convertDateTimeTupleToDateYYYYMMDD((2113, 12, 31, 24, 51, 18, 2, 317, 0))
        Traceback (most recent call last):
        ValueError: hour out of range
        >>> convertDateTimeTupleToDateYYYYMMDD((2113, 12, 31, 23, 61, 18, 2, 317, 0))
        Traceback (most recent call last):
        ValueError: minute out of range
        >>> convertDateTimeTupleToDateYYYYMMDD((2113, 12, 31, 23, 59, 62, 2, 317, 0))
        Traceback (most recent call last):
        ValueError: seconds out of range
        
        Valid leap second 61:
        >>> convertDateTimeTupleToDateYYYYMMDD((2113, 12, 31, 23, 59, 61, 2, 317, 0))
        '21131231'

        Before the Epoch:
        >>> convertDateTimeTupleToDateYYYYMMDD((1969, 7, 16, 13, 51, 18, 2, 317, 0))
        '19690716'
        
        Way before the Epoch:
        >>> convertDateTimeTupleToDateYYYYMMDD((1917, 7, 16, 13, 51, 18, 2, 317, 0))
        '19170716'
        
        Around the earliest accepted year (1900):
        >>> convertDateTimeTupleToDateYYYYMMDD((1899, 12, 31, 23, 59, 59, 0, 0, 0))
        Traceback (most recent call last):
        ValueError: year out of range
        >>> convertDateTimeTupleToDateYYYYMMDD((1900, 1, 1, 0, 0, 0, 0, 0, 0))
        '19000101'
        
        Ancient times before 1900:
        >>> convertDateTimeTupleToDateYYYYMMDD((1817, 7, 16, 13, 51, 18, 2, 317, 0))
        Traceback (most recent call last):
        ValueError: year out of range
        
        Way way before the Epoch makes the program guess you probably meant something
        else than what you wrote:
        >>> convertDateTimeTupleToDateYYYYMMDD((69, 7, 16, 13, 51, 18, 2, 317, 0))
        '19690716'
    '''
    dateYYYYMMDD = time.strftime('%Y%m%d', lastTimeDateTimeTuple)
    return dateYYYYMMDD


def convertDateYYYYMMDDToSecondsSinceEpoch(dateYYYYMMDD):
    '''
    Convert a date in the form "20130716" (for July 16, 2013) to seconds 
    since the system Epoch (on Unix the Epoch is 00:00:00 UTC on January 1, 1970, 
    see http://docs.python.org/2/library/time.html).
    
    JH: It seems like the Windows Epoch is really in 1601, according to 
    http://stackoverflow.com/questions/8670610/conversion-of-unix-epoch-time-to-windows-epoch-time-in-python,
    but on Windows 7, Python 2.7.5, time.gmtime(0) gives an epoch of 1970-01-01.
    I wonder what time.gmtime(0) gives on a Mac? And in Linux?

    :param dateYYYYMMDD:
        A date string in the form "YYYYMMDD", such as "20130726" for July 26, 2013.

    Docstring tests:
    
        Converting the Epoch date itself does not always work, at least not 
        in Denmark. But I (JH) cannot come up with a test that shows it, as 
        it depends on the current locale which is difficult to set up before 
        the test. But in Denmark, on Windows 7, this is the result:
        #>>> convertDateYYYYMMDDToSecondsSinceEpoch("19700101")
        #Traceback (most recent call last):
        #OverflowError: mktime argument out of range
        
        JH: Note that the above could create problems when the Epoch is used
        as a default date (which it is in this program). This function cannot 
        always convert the representation of the Epoch "19700101" back into 
        seconds since the Epoch. Perhaps it works in the US (?), but not in 
        Europe, at least definitely not in Denmark according to my tests.

        But January 2, 1970, seems to work. The precise amount of seconds
        returned depends on the locale, so we test within two days:
        >>> convertDateYYYYMMDDToSecondsSinceEpoch("19700102") in range (0, 2*24*60*60)
        True
    '''
    secondsSinceEpoch = time.mktime(time.strptime(dateYYYYMMDD, '%Y%m%d'))
    return secondsSinceEpoch
